#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<bits/stdc++.h>
#include<string>
#include<algorithm>
#include<sys/wait.h>
#include<sys/stat.h>
#include<fcntl.h>
using namespace std;
#define IN  0
#define OUT 1
#define APPEND_OUT 2 
#define NONE -1
string readfilename;
int rdir = NONE; 
const char* getusername()
{
  return getenv("USER");
}
const char* gethostname()
{
  return getenv("HOSTNAME");
}
//const char* getpwd()
//{
 // string pwd = getenv("PWD");
 // size_t pos = pwd.size() - 1;
 // while(pwd[pos--] != '/');
 // pos += 2;
 // return pwd.substr(pos).c_str(); 
//}
char Pwd[1024]; 
void getpwd()
{
  getcwd(Pwd,sizeof(Pwd));
}
#define LEFT "["
#define RIGHT "]"
#define LABLE "$"

void Print()
{
  getpwd();
  printf(LEFT "%s@%s %s" RIGHT "" LABLE " ""(模拟)",getusername(),gethostname(),Pwd);
}
string cmdline;
void check()
{
  //ls -a 
  //ls -a > readfilename 
  //ls -a >> readfilename  
  size_t i = 0;
  while(i < cmdline.size())
  {
      if(cmdline[i] == '>')
      {
          cmdline[i] = ' ';
          if(i + 1 < cmdline.size() && cmdline[i + 1] == '>')
          {  
             //append()
             rdir = APPEND_OUT;
             ++i;
             cmdline[i] = ' ';
             while(i < cmdline.size() && cmdline[i] == ' ')
             {
                ++i;                                                                                                                         }                                                                                               
            readfilename = cmdline.substr(i);  
               cmdline = cmdline.substr(0,i);
              //cout << readfilename << endl;
              //cout << cmdline << endl;
              // exit(0);
             //readfilename ....
             return ;
          }
          rdir = OUT;
          while(i < cmdline.size() && cmdline[i] == ' ')
          {
               ++i;                                                                                                                       }                                                                                               
         // readfilename = ....
             readfilename = cmdline.substr(i);  
          
          cmdline = cmdline.substr(0,i);
      }
      else if(cmdline[i] == '<') 
      {
         cmdline[i] = ' '; 
         rdir = IN;
         while(i < cmdline.size() && cmdline[i] == ' ')
         {
           ++i;
         }
         readfilename = cmdline.substr(i);
         cmdline = cmdline.substr(0,i);
      }
      else 
      {
           //do nothing
      }
      ++i;
  }
}
void Interact()
{
  
  Print();
  getline(cin,cmdline);
  while(cmdline.size() == 0)
  {
     Print();
     getline(cin,cmdline);
  }
  //cout << cmdline << endl;
  //C语言就用char* s = fgets(cmdline,sizeof(cmdline),stdin);
  //用s的返回值来判断
  //
  //
  

  //ls -a -l > myfile
  check();
}

char* tmp[1024];
vector<string> argv;
//char* argv[1024];
void split()
{
  string s;
  //      ls     la
  for(size_t i = 0;i < cmdline.size();++i)
  {
    if(cmdline[i] == ' ')
    {
        if(s.size())
        {
         argv.push_back(s);
          s.clear();
        }   
    }
    else s += cmdline[i];
   }
  if(s.size()) argv.push_back(s);
  if(argv[0] == "ls"){
    argv.push_back("--color");
  }
 //C语言字符串分割使用strtok
  //char *strtok(char *str, const char *delim); 
 //调一次只会截出来一个字串,必须循环调用
 //argv[i++] = strtok(str," ")
 //while(argv[i++] = strtok(NULL," "));
 //且第一次调用用str,之后调用第一个参数都为NULL
 //strtok会修改原字符串
 
 
 //验证-debug
     // for(auto e : argv) cout << e << endl;
     
     for(size_t i = 0; i < argv.size();++i)
     {
       tmp[i] = new char[argv[i].size() + 1];
       strcpy(tmp[i],argv[i].c_str());
       tmp[i][argv[i].size()] = '\0';
     }
     
     tmp[argv.size()] = NULL;

    // for(size_t i = 0;i < argv.size();++i)
    // { 
    //    cout << tmp[i] << endl;
    // }
}
int lastcode = 0;
void NormalCommand()
{
   pid_t id = fork(); 
   if(id < 0)
   {
     perror("fork");
     return ;
   }
   else if(id == 0)
   {
     //子进程执行命令 
     

     //重定向的原理
     //做了重定向的工作,不影响程序替换吗?
     //程序替换是改一下代码和数据,改一下页表,和文件那边没关系
     //进程历史打开的文件与进行的各种重定向关系
     //都和未来进行程序替换无关!
     int fd = 0;
     if(rdir == IN)
     {
       // cout << readfilename << endl;
       // cout << "IN" << readfilename <<  endl;
        fd = open(readfilename.c_str(),O_RDONLY);
        dup2(fd,0);
     }
     else if(rdir == OUT)
     {
        //ls -a > log.txt  -- 1.> -> ' ' 
       // cout << "OUT" << endl;
        fd = open(readfilename.c_str(),O_CREAT|O_WRONLY|O_TRUNC,0666);
        dup2(fd,1);
     }
     else if(rdir ==APPEND_OUT)
     {
       // cout << "APPEND" << endl;
        fd = open(readfilename.c_str(),O_CREAT|O_WRONLY|O_APPEND,0666);
        dup2(fd,1);
     }
     execvpe(tmp[0],tmp,environ);
     exit(44);
   }
   else 
   {
     int status = 0;
     pid_t ret = waitpid(id,&status,0);
     if(ret == id)
     {
        lastcode = WEXITSTATUS(status); 
     }
   }

}
//自定义环境变量表
char env[1024];

//自定义本地变量表

int Build_in_Command()
{ 
  if(argv.size() == 2 && argv[0] == "cd")
  {
    chdir(tmp[1]);
    getpwd();
    sprintf(getenv("PWD"),"%s",Pwd);
    return 1;
  }
 else if(argv.size() == 2 && argv[0] == "export")
  {
     //cout << tmp[1] << endl;
     //char t[1024];
    // strcpy(t,argv[1].c_str());
     //cout <<t << endl;
    //setenv((char*)t);
     //cout << 111 << endl;
    // cout << (tmp[1]) << endl;
   // int i = 0;
   // while(tmp[1][i] != '\0') i++;
   // 导环境变量,不是将字符串拷贝进去！而是指针指向过去
   // char* env[]表里面没有字符串,存放的都是指针!
   // 如果用的是putenv(tmp[i])，
   // 下一次输出环境变量的时候这块指向的内容早就改变了!
   // 这就解释了全局变量不会出错的问题!因为它不会改变指向！
   // 别忘了这是一个进程！while循环不断输入输出
   // 完美的解释了上面的错误原因！
   //  putenv(tmp[1]); 
     strcpy(env,tmp[1]);
     putenv(env);
     return 1;
  }
  else if(argv.size() == 2 && argv[0] == "echo")
  {
    if(argv[1] == "$?")
    {
      printf("%d\n",lastcode);
      lastcode = 0;
    }
    else if(argv[1][0] == '$')
    {
      printf("%s\n",getenv(argv[1].substr(1).c_str()));
    }
    else
    {
      printf("%s\n",argv[1].c_str());
    }
     return 1;
  }
  return 0;
}
void DEL()
{
   for(size_t i = 0; i < argv.size();++i)
   {
     delete[] tmp[i];
   }
   argv.clear();
}
int main()
{
  extern char** environ;
 while(1)
 {
   rdir = NONE;
   readfilename.clear();
   //ls -a -l > myfile / ls -a -l >> myfile
  Interact();
  split(); 
  //指令的判断 内建or普通
  //普通命令的执行
  //if(argv[0] != "cd" && argv[0] != "echo")
  //NormalCommand();
  //else Build_in_Command();
  //内建命令,本质就是shell内部的一个函数 
 int r =  Build_in_Command();
 if(r == 0)
 {
   NormalCommand();
 }

 DEL();
 }
  return 0;
}
